﻿using OpenCvSharp;
using OpenCvSharp.Features2D;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Xml.Linq;
using static OpenCvSharp_ImageRecognition.Servers;

namespace OpenCvSharp_ImageRecognition
{
    /// <summary>
    /// IOpenCvSharp4_图像识别接口
    /// </summary>
    public interface IOpenCvSharp4_图像识别接口
    {
        /// <summary>
        /// 开始进行图像识别，传入图片路径，log表示是否打开log图片开关，默认打开
        /// </summary>
        /// <param name="pngPath">图片路径</param>
        /// <param name="制式模式">2G、3G、4G、5G、wifi</param>
        /// <param name="设备类型">平板、手表、其他</param>
        /// <param name="最大匹配值">默认0.999999</param>
        /// <param name="log">log表示是否打开log图片开关，默认打开</param>
        /// <returns>返回string[],其中T1=模式，T2表示信号格数</returns>
        Task<Tuple<bool, string[]>> ImageRecognitionAsync(string pngPath, Mode 制式模式, DeviceType 设备类型, double 最大匹配值 = 0.999999, bool log = true);
        /// <summary>
        /// 设置信号格优先级，用于提升识别速度
        /// </summary>
        /// <param name="Signal"></param>
        void Prioritylevel(Signal Signal);

    }


    /// <summary>
    /// 通过识别服务
    /// </summary>
    public class Servers : IOpenCvSharp4_图像识别接口
    {
        public double 最大匹配值 = double.NaN, 匹配阈值 = double.NaN;
        string 模板图片;
        string 手表待检图;
        private string 截图_log;
        private string logpath;
        private bool tplog = true;
        private Tuple<bool, string, double[]> 识别是否成功 = null;  //是否成功，文件夹名称（识别结果），结果的内容 最大值等等
        Signal signal;
        Mode 制式模式;
        DeviceType 设备类型;
        CancellationTokenSource cts; //线程通知；
        /// <summary>
        /// 当前程序运行路径
        /// </summary>
        /// <param name=""></param>
        public Servers()
        {

            最大匹配值 = 0.999999; 匹配阈值 = 0.9;
            Directory.CreateDirectory(Path.Combine(Environment.CurrentDirectory, "图片识别\\OpenCvSharp4_log\\截图"));
            string llog = Directory.CreateDirectory(Path.Combine(Environment.CurrentDirectory, "图片识别\\OpenCvSharp4_log\\OpenCv_log")).FullName;
            模板图片 = Directory.CreateDirectory(Path.Combine(Environment.CurrentDirectory, "图片识别\\模板图片")).FullName;
            string watch_wifi = Path.Combine(Environment.CurrentDirectory, "图片识别\\模板图片\\手表\\wifi");
            string watch_制式2G = Path.Combine(Environment.CurrentDirectory, "图片识别\\模板图片\\手表\\2G");
            string watch_制式3G = Path.Combine(Environment.CurrentDirectory, "图片识别\\模板图片\\手表\\3G");
            string watch_制式4G = Path.Combine(Environment.CurrentDirectory, "图片识别\\模板图片\\手表\\4G");
            string watch_制式5G = Path.Combine(Environment.CurrentDirectory, "图片识别\\模板图片\\手表\\5G");
            string pb_wifi = Path.Combine(Environment.CurrentDirectory, "图片识别\\模板图片\\平板\\wifi");
            string qt_wifi = Path.Combine(Environment.CurrentDirectory, "图片识别\\模板图片\\其他\\wifi");
            string qt_制式2G = Path.Combine(Environment.CurrentDirectory, "图片识别\\模板图片\\其他\\2G");
            string qt_制式3G = Path.Combine(Environment.CurrentDirectory, "图片识别\\模板图片\\其他\\3G");
            string qt_制式4G = Path.Combine(Environment.CurrentDirectory, "图片识别\\模板图片\\其他\\4G");
            string qt_制式5G = Path.Combine(Environment.CurrentDirectory, "图片识别\\模板图片\\其他\\5G");
            //创建模版图片文件夹
            for (int i = 0; i < 5; i++)
            {
                string aaw = "wifi-" + i.ToString();
                string aa2 = "2G-" + i.ToString();
                string aa3 = "3G-" + i.ToString();
                string aa4 = "4G-" + i.ToString();
                string aa5 = "5G-" + i.ToString();
                Directory.CreateDirectory(Path.Combine(watch_wifi, aaw));
                Directory.CreateDirectory(Path.Combine(watch_制式2G, aa2));
                Directory.CreateDirectory(Path.Combine(watch_制式3G, aa3));
                Directory.CreateDirectory(Path.Combine(watch_制式4G, aa4));
                Directory.CreateDirectory(Path.Combine(watch_制式5G, aa5));

                Directory.CreateDirectory(Path.Combine(pb_wifi, aaw));
                Directory.CreateDirectory(Path.Combine(qt_wifi, aaw));
                Directory.CreateDirectory(Path.Combine(qt_制式2G, aa2));
                Directory.CreateDirectory(Path.Combine(qt_制式3G, aa3));
                Directory.CreateDirectory(Path.Combine(qt_制式4G, aa4));
                Directory.CreateDirectory(Path.Combine(qt_制式5G, aa5));
            }


            手表待检图 = Directory.CreateDirectory(Path.Combine(Environment.CurrentDirectory, "图片识别\\手表待检图")).FullName;
            截图_log = Directory.CreateDirectory(Path.Combine(Environment.CurrentDirectory, "图片识别\\OpenCvSharp4_log\\截图")).FullName;
            Directory.CreateDirectory(Path.Combine(Environment.CurrentDirectory, "图片识别\\OpenCvSharp4_log\\OpenCv_log"));
            string date = DateTime.Now.ToString("yyyy-MM-dd");//LogFile-2023-11-18
            logpath = Path.Combine(llog, "OpenCvSharp4-" + date + ".log");
        }
        /// <summary>
        /// 开始进行图像识别，传入图片路径，log表示是否打开log图片开关，默认打开
        /// </summary>
        /// <param name="pngPath">图片路径</param>
        /// <param name="制式模式">2G、3G、4G、5G、wifi</param>
        /// <param name="设备类型">平板、手表、其他</param>
        /// <param name="最大匹配值">默认0.999999</param>
        /// <param name="log">log表示是否打开log图片开关，默认打开</param>
        /// <returns>返回string[],其中T1=模式，T2表示信号格数</returns>
        public async Task<Tuple<bool, string[]>> ImageRecognitionAsync(string pngPath, Mode 制式模式, DeviceType 设备类型, double 最大匹配值 = 0.999999, bool log = true)
        {

            cts = new CancellationTokenSource();
            this.最大匹配值 = 最大匹配值;
            string[] 匹配结果 = null;
            识别是否成功 = null;
            this.制式模式 = 制式模式;
            this.设备类型 = 设备类型;
            switch (this.设备类型)
            {
                case DeviceType.平板:
                    模板图片 = Directory.CreateDirectory(Path.Combine(Environment.CurrentDirectory, "图片识别\\模板图片\\平板")).FullName;

                    break;
                case DeviceType.手表:
                    模板图片 = Directory.CreateDirectory(Path.Combine(Environment.CurrentDirectory, "图片识别\\模板图片\\手表")).FullName;

                    break;
                case DeviceType.其他:
                    模板图片 = Directory.CreateDirectory(Path.Combine(Environment.CurrentDirectory, "图片识别\\模板图片\\其他")).FullName;
                    break;
                default:
                    Write("设备类型不存在:" + 设备类型, "Error");
                    return new Tuple<bool, string[]>(false, 匹配结果);

            }
            switch (this.制式模式)
            {
                case Mode.wifi:
                    模板图片 = Path.Combine(模板图片, "wifi");
                    break;
                case Mode.G2:
                    模板图片 = Path.Combine(模板图片, "2G");
                    break;
                case Mode.G3:
                    模板图片 = Path.Combine(模板图片, "3G");
                    break;
                case Mode.G4:
                    模板图片 = Path.Combine(模板图片, "4G");
                    break;
                case Mode.G5:
                    模板图片 = Path.Combine(模板图片, "5G");
                    break;
                default:
                    return new Tuple<bool, string[]>(false, 匹配结果);
            }
            if (!File.Exists(pngPath))
            {
                Write("文件不存在:" + pngPath, "Error");
                return new Tuple<bool, string[]>(false, 匹配结果);
            }
            Write("开始识别", "Debug");
            Write("原始图片:" + pngPath, "Debug");
            Write("模板图片:" + 模板图片, "Debug");
            Write("制式模式选择:" + this.制式模式, "Debug");
            Write("设备类型:" + this.设备类型, "Debug");
            Write("预测参数最大匹配值:" + 最大匹配值, "Debug");
            Write("预测参数匹配阈值:" + 匹配阈值, "Debug");
            tplog = log;
            string newpng = Path.Combine(手表待检图, Path.GetFileName(pngPath));
            bool a = CopyFile(pngPath, newpng);
            if (a)
            {
                await 实现目录识别方法(this.制式模式);
            }
            if (识别是否成功 != null)
            {
                if (识别是否成功.Item1)
                {
                    string wjj = 识别是否成功.Item2;//文件夹名称
                    double[] 结果 = 识别是否成功.Item3; //double[]= 最大匹配度，最大位置X，Y,最小位置X,Y；
                    string[] bae = wjj.Split('-');
                    if (bae.Length > 0)
                    {
                        匹配结果 = new string[] { bae[0], bae[1] };
                        return new Tuple<bool, string[]>(true, 匹配结果);
                    }
                }
            }
            return new Tuple<bool, string[]>(false, 匹配结果);
        }
        /// <summary>
        /// 设置信号格优先级，用于提升识别速度
        /// </summary>
        public void Prioritylevel(Signal Signal)
        {
            this.signal = Signal;
            Console.WriteLine("设置信号格优先级:" + Signal);
        }
        private async Task 实现目录识别方法(Mode mode)
        {

            if (double.IsNaN(最大匹配值) | (double.IsNaN(匹配阈值)))
            {
                Write("最大匹配值:" + 最大匹配值 + "必须正确填写", "Error");
                Write("匹配阈值:" + 匹配阈值 + "必须正确填写", "Error");
                return;
            }

            if (!Directory.Exists(模板图片))
            {
                Write("发生错误: 模板图片文件夹不存在", "Error");
                return;
            }
            try
            {
                string[] subDirectories = Directory.GetDirectories(模板图片);
                if (!Directory.Exists(手表待检图))
                {
                    Write("发生错误: 手表待检图文件夹不存在", "Error");
                    return;
                }
                string[] filepath = Directory.GetFiles(手表待检图);

                if (filepath.Length != 1)
                {
                    Write($"手表待检图:没有图片或者图片数量过多，只能有一张图片存在：图片目前数量为：{filepath.Length}", "Error");
                    return;
                }
                byte[] 原始数据组 = File.ReadAllBytes(filepath[0]);
                //如果是平板   拿到的是一个wifi目录 WiFi目录下又有许多信号格文件夹
                List<string> modelist = 模式文件夹(subDirectories, mode);
                if (signal != null)
                {
                    modelist.Sort((x, y) =>
                    {
                        int lastDigitX = int.Parse(x.Substring(x.Length - 1));
                        int lastDigitY = int.Parse(y.Substring(y.Length - 1));

                        if (lastDigitX == (int)signal)
                        {
                            return -1; // 将以 1 结尾的字符串排在前面
                        }
                        else if (lastDigitY == (int)signal)
                        {
                            return 1; // 将以 1 结尾的字符串排在前面
                        }
                        else
                        {
                            return x.CompareTo(y); // 其他字符串按字典顺序排序
                        }
                    });
                }
                List<Task> tasks = new List<Task>();
                foreach (var item in modelist)
                {
                    //Write("***模式下文件夹: " + item, "Debug");
                    if (cts.IsCancellationRequested)  //再启动线程前检查线程取消令牌
                    {
                        Console.WriteLine($"Thread.CurrentThread.Name:{Thread.CurrentThread.Name}:Task will not start because cancellation has been requested.");
                        return;
                    }
                    var task = Task.Run(() =>
                    {
                        bool a = 图形识别文件夹(item, 原始数据组, filepath[0]);
                        if (a)
                        {
                            cts.Cancel(); // 取消其它任务
                        }
                        return a;
                    }, cts.Token);

                    tasks.Add(task);
                }

                try
                {
                    await Task.WhenAll(tasks.ToArray());
                }
                catch (OperationCanceledException)
                {
                    Console.WriteLine("One or more tasks were cancelled.");
                }

                // 执行最终的判断方法
                //   FinalJudgement();


            }
            catch (Exception ex)
            {
                Write("发生错误: " + ex, "Error");
            }

        }

        /// <summary>
        /// 文件夹图片识别
        /// </summary>
        /// <param name="dir"></param>
        private bool 图形识别文件夹(string dir, byte[] 原始数据组, string 原始数据图路径)
        {
            string 记录当前文件夹名称 = new DirectoryInfo(dir).Name;
            // Write("记录当前文件夹名称:" + 记录当前文件夹名称, "Debug");
            ImageIdentification imageIdentification = new ImageIdentification(匹配阈值, 最大匹配值, this.logpath, cts);
            //  Write("匹配阈值:" + 匹配阈值, "Debug");
            // Console.WriteLine($"匹配阈值:{匹配阈值}  最大匹配值:{最大匹配值}");
            if (cts.Token.IsCancellationRequested)
            {  //如果任务取消，进入该处进行停止线程
                Console.WriteLine($"Thread.CurrentThread.Name:{Thread.CurrentThread.Name}:Task  is cancelling.");
                cts.Token.ThrowIfCancellationRequested();
            }

            bool a = imageIdentification.Run_多模型单图片识别_内存(dir, 原始数据组, out double[] 结果);
            if (cts.Token.IsCancellationRequested)
            {  //如果任务取消，进入该处进行停止线程
                Console.WriteLine($"Task  is cancelling.");
                cts.Token.ThrowIfCancellationRequested();
            }
            if (tplog) //是否打开log
            {
                if (a)
                {
                    //匹配成功的
                    // Write($"Run_多模型单图片识别_内存:{a},结果长度：{结果.Length}", "Debug");
                    识别是否成功 = new Tuple<bool, string, double[]>(true, 记录当前文件夹名称, 结果);
                    Write(记录当前文件夹名称 + $"    {结果[0]}识别到图片：" + 原始数据图路径 + ":匹配成功", "Debug");
                    CopyFileAsync(原始数据图路径, Path.Combine(截图_log, $"Pass - ({Path.GetFileNameWithoutExtension(原始数据图路径)})-({DateTime.Now.ToString("yyMMdd-HHmmss")})-({记录当前文件夹名称}-{ 结果[0] }).png")); //复制到log文件夹

                    return true;
                }
                else
                {
                    CopyFileAsync(原始数据图路径, Path.Combine(截图_log, $"Fail - ({Path.GetFileNameWithoutExtension(原始数据图路径)})-({DateTime.Now.ToString("yyMMdd-HHmmss")})-({记录当前文件夹名称}).png")); //复制到log文件夹
                }
            }
            else
            {
                //没有打开log'
                if (a)
                {
                    //匹配成功的
                    //  Write($"Run_多模型单图片识别_内存:{a},结果长度：{结果.Length}", "Debug");
                    识别是否成功 = new Tuple<bool, string, double[]>(true, 记录当前文件夹名称, 结果);
                    Write(记录当前文件夹名称 + $"    {结果[0]}识别到图片：" + 原始数据图路径 + ":匹配成功", "Debug");
                    return true;
                }
            }
            return false;
        }
        private List<string> 模式文件夹(string[] subDirectories, Mode mode)
        {
            List<string> listmode_wifi = new List<string>();
            List<string> listmode_2G = new List<string>();
            List<string> listmode_3G = new List<string>();
            List<string> listmode_4G = new List<string>();
            List<string> listmode_5G = new List<string>();
            if (subDirectories.Length > 0)
            {
                foreach (string subDirectory in subDirectories)
                {
                    string 记录当前文件夹名称 = new DirectoryInfo(subDirectory).Name;
                    switch (mode)
                    {
                        case Mode.wifi:
                            if (记录当前文件夹名称.Contains("wifi"))
                            {
                                listmode_wifi.Add(subDirectory);
                            }
                            break;
                        case Mode.G2:
                            if (记录当前文件夹名称.Contains("2G"))
                            {
                                listmode_2G.Add(subDirectory);
                            }
                            break;
                        case Mode.G3:
                            if (记录当前文件夹名称.Contains("3G"))
                            {
                                listmode_3G.Add(subDirectory);
                            }
                            break;
                        case Mode.G4:
                            if (记录当前文件夹名称.Contains("4G"))
                            {
                                listmode_4G.Add(subDirectory);
                            }
                            break;
                        case Mode.G5:
                            if (记录当前文件夹名称.Contains("5G"))
                            {
                                listmode_5G.Add(subDirectory);
                            }
                            break;
                        default:
                            Write(subDirectory + ": 不存在，不属于任何文件夹", "Error");  //错误
                            break;
                    }
                }
                switch (mode)
                {
                    case Mode.wifi:
                        return listmode_wifi;
                    case Mode.G2:
                        return listmode_2G;
                    case Mode.G3:
                        return listmode_3G;
                    case Mode.G4:
                        return listmode_4G;
                    default:
                        return new List<string>();
                }
            }
            else
            {
                return new List<string>();
            }
        }
        /// <summary>
        /// 复制文件
        /// </summary>
        /// <param name="sourceFilePath"></param>
        /// <param name="destinationFilePath"></param>
        /// <returns></returns>
        public bool CopyFile(string sourceFilePath, string destinationFilePath)
        {
            try
            {
                // 打开源文件和目标文件的 FileStream
                using (FileStream sourceStream = new FileStream(sourceFilePath, FileMode.Open, FileAccess.Read))
                using (FileStream destinationStream = new FileStream(destinationFilePath, FileMode.Create, FileAccess.Write))
                {
                    byte[] buffer = new byte[4096]; // 缓冲区大小，可以根据需求进行调整
                    int bytesRead;

                    // 逐个读取源文件的字节，并将其写入目标文件
                    while ((bytesRead = sourceStream.Read(buffer, 0, buffer.Length)) > 0)
                    {
                        destinationStream.Write(buffer, 0, bytesRead);
                    }
                }
                return true;
            }
            catch (Exception e)
            {
                Write("CopyFile:" + e, "Error");
                return false;
            }

        }
        /// <summary>
        /// Async复制文件
        /// </summary>
        /// <param name="sourceFilePath"></param>
        /// <param name="destinationFilePath"></param>
        /// <returns></returns>
        public async Task<bool> CopyFileAsync(string sourceFilePath, string destinationFilePath)
        {
            try
            {
                using (FileStream sourceStream = new FileStream(sourceFilePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
                using (FileStream destinationStream = new FileStream(destinationFilePath, FileMode.Create, FileAccess.Write, FileShare.ReadWrite))
                {
                    byte[] buffer = new byte[4096]; // 缓冲区大小，可以根据需求进行调整
                    int bytesRead;

                    while ((bytesRead = await sourceStream.ReadAsync(buffer, 0, buffer.Length)) > 0)
                    {
                        await destinationStream.WriteAsync(buffer, 0, bytesRead);
                    }
                }
                return true;
            }
            catch (Exception e)
            {
                Write("CopyFileAsync:" + e, "Error");
                return false;
            }
        }
        private static object _lock = new object(); //写文件加锁
        void Write(string str, string 错误级别)
        {
            lock (_lock)
            {
                string a = DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss.fff");
                string stre = a + "\t" + this.GetType().Name + "\t" + 错误级别 + "\t" + str;
                Console.WriteLine(stre);
                using (StreamWriter streamWriter = new StreamWriter(logpath, true))
                {
                    streamWriter.WriteLine(stre);
                    streamWriter.Close();
                }
            }
        }

        public enum DeviceType
        {
            平板 = 1,
            手表 = 2,
            其他 = 3,
        }

        /// <summary>
        /// 模式,1=wifi，2=2G，3=3G，4=4G,5=5G
        /// </summary>
        public enum Mode
        {
            wifi = 1,
            G2 = 2,
            G3 = 3,
            G4 = 4,
            G5 = 5
        }
        public enum Signal
        {
            Signal_0 = 0,
            Signal_1 = 1,
            Signal_2 = 2,
            Signal_3 = 3,
            Signal_4 = 4
        }
    }
    class ImageIdentification
    {
        private double 匹配阈值 = 0.5;
        private double 最大匹配值 = 0.5;
        private string logpath;
        CancellationTokenSource cts;
        public ImageIdentification(double 匹配阈值, double 最大匹配值, string logpath, CancellationTokenSource cts)
        {
            this.匹配阈值 = 匹配阈值;
            this.最大匹配值 = 最大匹配值;
            this.logpath = logpath;
            this.cts = cts;
            // this.MyDataList = MyData;
            //   this.dispatcher= dispatcher;    
        }
        #region    单模型识别 以字节数组方式识别
        public bool Run_单模型单图片识别_内存(string dir_模板文件夹, byte[] imageData, string 结果)
        {
            //Write("开始检测");
            bool mo = false;
            string currentDirectory = Directory.GetCurrentDirectory();
            string 所有 = currentDirectory + "\\图片识别\\所有图片";
            string 待匹配 = currentDirectory + "\\图片识别\\单模板图片";
            string[] aa = Directory.GetFiles(dir_模板文件夹);
            if (aa == null || aa.Length == 0)
            {
                Write("单模型没有图片模板", "Error");
                return mo = false;
            }
            // 加载目标图片和待匹配图片
            Mat targetImage = Cv2.ImRead(aa[0]);  //所有图片的其中一个
            //Mat matchImage = Cv2.ImRead(待匹配 + "\\匹配2.png");//需要匹配成功的图片     
            Mat matchImage = new Mat();
            matchImage = Cv2.ImDecode(imageData, ImreadModes.Color); ;//需要匹配成功的图片 
            // 进行模板匹配
            Mat result = new Mat();
            Cv2.MatchTemplate(targetImage, matchImage, result, TemplateMatchModes.CCoeffNormed);
            // 寻找最佳匹配位置
            double minVal, maxVal;
            OpenCvSharp.Point minLoc, maxLoc;
            Cv2.MinMaxLoc(result, out minVal, out maxVal, out minLoc, out maxLoc);
            //Write("匹配度信息：" + maxVal);
            //  Write("匹配位置信息：" + maxLoc);
            // 如果找到匹配的位置
            if (maxVal > 最大匹配值)
            {
                // 输出结果
                Write("找到匹配的图片！", "Debug");
                Write("匹配度：" + maxVal, "Debug");
                Write("匹配位置：" + maxLoc, "Debug");
                mo = true;
            }
            else
            {
                // Write("未找到匹配的图片。");
                mo = false;
            }

            // 释放资源
            targetImage.Release();
            matchImage.Release();
            result.Release();
            return mo;
        }
        #endregion
        #region 多模型识别  以字节数组方式识别
        /// <summary>
        /// 开始识别图标算法
        /// </summary>
        /// <param name="dir_模板文件夹">模板文件夹</param>
        /// <param name="待检图片文件夹">待检图片文件夹</param>
        public bool Run_多模型单图片识别_内存(string dir_模板文件夹, byte[] imageData, out double[] 结果)
        {

            if (cts.Token.IsCancellationRequested)
            {  //如果任务取消，进入该处进行停止线程
                Console.WriteLine($"Thread.CurrentThread.Name:{Thread.CurrentThread.Name}:线程正在取消... Run_多模型单图片识别_内存");
                cts.Token.ThrowIfCancellationRequested();
            }
            结果 = new double[0];
            if (!Directory.Exists(dir_模板文件夹))
            {
                return false;
            }
            string[] files_模板 = Directory.GetFiles(dir_模板文件夹);

            if (files_模板.Length == 0 || files_模板 == null)
            {
                Write("多模板文件夹没有模板图片！", "Error");
                return false;
            }

            //把读取的文件模板图，加载进识别列表
            List<Mat> templates = new List<Mat>();
            foreach (var item in files_模板)
            {
                if (cts.Token.IsCancellationRequested)
                {  //如果任务取消，进入该处进行停止线程

                    Console.WriteLine($"Thread.CurrentThread.Name:{Thread.CurrentThread.Name}:线程正在取消...  foreach (var item in files_模板)");
                    cts.Token.ThrowIfCancellationRequested();
                }
                templates.Add(Cv2.ImRead(item, ImreadModes.Color));

            }

            var a = 图片算法算法检测(templates, imageData);

            if (a.Item1)
            {
                结果 = a.Item2;
            }

            return a.Item1;
        }
        private bool 单图像识别(string dir_模板文件夹, byte[] imageData, string 结果)
        {
            string[] files_模板 = Directory.GetFiles(dir_模板文件夹);
            if (files_模板.Length == 0 || files_模板 == null)
            {
                Write("多模板文件夹没有模板图片！", "Error");

                return false;
            }
            //把读取的文件模板图，加载进识别列表
            List<Mat> templates = new List<Mat>();
            foreach (var item in files_模板)
            {
                templates.Add(Cv2.ImRead(item, ImreadModes.Color));

            }
            return 算法检测(templates, imageData);


        }
        private Tuple<bool, double[]> 图片算法算法检测(List<Mat> templates, byte[] imageData)
        {
            bool bl = false;//默认没有检测到
                            //Write("开始检测" );
                            //Mat targetImg = new Mat();
                            //targetImg = Cv2.ImDecode(imageData, ImreadModes.Color);
                            //// 添加更多的模板...
                            //// 创建匹配结果矩阵列表
                            //List<Mat> results = new List<Mat>();      
                            //foreach (Mat template in templates)
                            //{
                            //    if (cts.Token.IsCancellationRequested)
                            //    {  //如果任务取消，进入该处进行停止线程
                            //        Console.WriteLine($"Thread.CurrentThread.Name:{Thread.CurrentThread.Name}:线程正在取消... Mat template in templates");
                            //        template.Release(); // 释放模板资源
                            //        targetImg.Dispose();
                            //        cts.Token.ThrowIfCancellationRequested();
                            //    }
                            //    Mat result = new Mat();
                            //    Cv2.MatchTemplate(targetImg, template, result, TemplateMatchModes.CCoeffNormed);
                            //    results.Add(result);
                            //    // template.Release(); // 释放模板资源
                            //}

            Mat targetImg = new Mat();
            targetImg = Cv2.ImDecode(imageData, ImreadModes.Color);
            // 添加更多的模板...
            // 创建匹配结果矩阵列表
            List<Mat> results = new List<Mat>();
            Parallel.ForEach(templates, template =>
            {
                if (cts.Token.IsCancellationRequested)
                {
                    Console.WriteLine($"Thread.CurrentThread.Name:{Thread.CurrentThread.Name}:线程正在取消... Mat template in templates");
                    template.Release(); // 释放模板资源
                    targetImg.Dispose();
                    cts.Token.ThrowIfCancellationRequested();
                }

                Mat result = new Mat();
                //Cv2.MatchTemplate(targetImg, template, result, TemplateMatchModes.CCoeffNormed);//SqDiff
                Cv2.MatchTemplate(targetImg, template, result, TemplateMatchModes.CCoeffNormed);//SqDiff
                results.Add(result);
                // template.Release(); // 释放模板资源
            });
            // 设置匹配阈值，根据需求调整
            double threshold = 匹配阈值;

            // 处理匹配结果
            for (int i = 0; i < results.Count; i++)
            {
                if (cts.Token.IsCancellationRequested)
                {  //如果任务取消，进入该处进行停止线程
                    Console.WriteLine($"Thread.CurrentThread.Name:{Thread.CurrentThread.Name}:线程正在取消... 处理匹配结果");
                    results = null; // 释放模板资源
                    targetImg.Dispose();
                    cts.Token.ThrowIfCancellationRequested();
                }
                for (int y = 0; y < results[i].Rows; y++)
                {
                    if (cts.Token.IsCancellationRequested)
                    {  //如果任务取消，进入该处进行停止线程
                        Console.WriteLine($"Thread.CurrentThread.Name:{Thread.CurrentThread.Name}:线程正在取消... y < results[i].Rows; y++");
                        results = null; // 释放模板资源
                        targetImg.Dispose();
                        cts.Token.ThrowIfCancellationRequested();
                    }
                    for (int x = 0; x < results[i].Cols; x++)
                    {
                        float data = results[i].Get<float>(y, x);
                        if (cts.Token.IsCancellationRequested)
                        {  //如果任务取消，进入该处进行停止线程
                            Console.WriteLine($"Thread.CurrentThread.Name:{Thread.CurrentThread.Name}:线程正在取消...   x < results[i].Cols; x++");
                            results = null; // 释放模板资源
                            targetImg.Dispose();
                            cts.Token.ThrowIfCancellationRequested();
                        }
                        if (data >= threshold)
                        {
                            // 找到匹配项，进行处理
                            //   Rect rectangle = new Rect(x, y, templates[i].Cols, templates[i].Rows);
                            //   Cv2.Rectangle(targetImg, rectangle, Scalar.Red, 2);

                            // 寻找最佳匹配位置
                            double minVal, maxVal;
                            OpenCvSharp.Point minLoc, maxLoc;
                            Cv2.MinMaxLoc(results[i], out minVal, out maxVal, out minLoc, out maxLoc);
                            //Write("结果：最大匹配度：" + maxVal, "Debug");
                            //  Write("结果：max匹配位置：" + maxLoc, "Debug");
                            // Write("结果：min匹配位置：" + minLoc, "Debug");

                            if (maxVal > 最大匹配值)
                            {
                                Write($"匹配成功：最大匹配度{maxVal},匹配位置{maxLoc}", "Debug");
                                bl = true;
                                return new Tuple<bool, double[]>(bl, new double[] { maxVal, maxLoc.X, maxLoc.Y, minLoc.X, minLoc.Y });
                            }
                            //  string resultImagePath = 结果 + "\\" + Path.GetFileNameWithoutExtension(imgpath) +"-"+new Random().Next(0,9999999)+ ".png";
                            // targetImg.SaveImage(resultImagePath);
                        }
                    }
                }
            }

            targetImg.Release(); // 释放资源

            return new Tuple<bool, double[]>(bl, new double[] { });
        }
        private Tuple<bool, double[]> 图片算法算法检测2(List<Mat> templates, byte[] imageData)
        {
          // Stopwatch stopwatch = new Stopwatch();
            // 开始计时
         //   stopwatch.Start();
            bool bl = false;//默认没有检测到

            // 加载目标图像
            Mat targetImg = new Mat();
            targetImg = Cv2.ImDecode(imageData, ImreadModes.Color);

            // 提取目标图像特征
            var sift = SIFT.Create();
            Mat targetDescriptors = new Mat();
            sift.DetectAndCompute(targetImg, null, out KeyPoint[] targetKeyPoints, targetDescriptors);

            // 创建匹配结果矩阵列表
            List<Mat> results = new List<Mat>();
            Mat template = new Mat(); ;
            Parallel.ForEach(templates, _template =>
            {
                if (cts.Token.IsCancellationRequested)
                {
                    Console.WriteLine($"Thread.CurrentThread.Name:{Thread.CurrentThread.Name}:线程正在取消... Mat template in templates");
                    _template.Release();
                    targetImg.Dispose();
                    cts.Token.ThrowIfCancellationRequested();
                }

                // 提取模板特征
                //   Mat templateDescriptors = new Mat();
                using (Mat templateDescriptors = new Mat())
                {

                    sift.DetectAndCompute(_template, null, out KeyPoint[] templateKeyPoints, templateDescriptors);

                    // 进行匹配
                    BFMatcher matcher = new BFMatcher(NormTypes.L2, false);
                    var matches = new DMatch[templateDescriptors.Rows][];
                    for (int i = 0; i < templateDescriptors.Rows; i++)
                    {
                        matches[i] = matcher.Match(templateDescriptors.Row(i), targetDescriptors);
                    }

                    // 获取匹配结果
                    Mat result = new Mat(new OpenCvSharp.Size(targetImg.Cols - _template.Cols + 1, targetImg.Rows - _template.Rows + 1), MatType.CV_32FC1, Scalar.All(0));
                    for (int i = 0; i < templateDescriptors.Rows; i++)
                    {
                        float[] distances = matches[i].Select(x => x.Distance).ToArray();
                        double maxDistance = Math.Max(distances.Max(), 1e-6);
                        for (int j = 0; j < matches[i].Length; j++)
                        {
                            int x = (int)targetKeyPoints[matches[i][j].TrainIdx].Pt.X - _template.Cols / 2;
                            int y = (int)targetKeyPoints[matches[i][j].TrainIdx].Pt.Y - _template.Rows / 2;
                            double weight = Math.Exp(-(distances[j] * distances[j]) / (2 * maxDistance * maxDistance));
                            Cv2.Rectangle(result, new Rect(x, y, _template.Cols, _template.Rows), new Scalar(weight), -1);
                        }
                    }
                    template = _template;
                    results.Add(result);

                }

            });
            // 设置匹配阈值，根据需求调整
            double threshold = 匹配阈值;
            // 处理匹配结果
            for (int i = 0; i < results.Count; i++)
            {
                if (cts.Token.IsCancellationRequested)
                {
                    Console.WriteLine($"Thread.CurrentThread.Name:{Thread.CurrentThread.Name}:线程正在取消... 处理匹配结果");
                    results = null;
                    targetImg.Dispose();
                    cts.Token.ThrowIfCancellationRequested();
                }

                // 将目标图像分块
                int blockWidth = 100;
                int blockHeight = 100;
                int numBlocksX = (int)Math.Ceiling((double)(targetImg.Cols - blockWidth + 1) / blockWidth);
                int numBlocksY = (int)Math.Ceiling((double)(targetImg.Rows - blockHeight + 1) / blockHeight);

                for (int j = 0; j < numBlocksY; j++)
                {
                    if (cts.Token.IsCancellationRequested)
                    {
                        Console.WriteLine($"Thread.CurrentThread.Name:{Thread.CurrentThread.Name}:线程正在取消... j < numBlocksY");
                        results = null;
                        targetImg.Dispose();
                        cts.Token.ThrowIfCancellationRequested();
                    }

                    for (int e = 0; e < numBlocksX; e++)
                    {
                        if (cts.Token.IsCancellationRequested)
                        {
                            Console.WriteLine($"Thread.CurrentThread.Name:{Thread.CurrentThread.Name}:线程正在取消... i < numBlocksX");
                            results = null;
                            targetImg.Dispose();
                            cts.Token.ThrowIfCancellationRequested();
                        }

                        // 获取当前块的 ROI
                        int x = e * blockWidth;
                        int y = j * blockHeight;

                        int width = Math.Min(blockWidth + template.Cols - 1, targetImg.Cols - x);
                        int height = Math.Min(blockHeight + template.Rows - 1, targetImg.Rows - y);
                        Rect roi = new Rect(x, y, width, height);

                        // 计算匹配结果
                        Mat blockResult = results[i].Clone();
                        // 添加边界检查
                        if (roi.Right > blockResult.Cols)
                        {
                            roi.Width = blockResult.Cols - roi.X;
                        }
                        // 检查传递的参数范围是否正确                   
                        blockResult = blockResult.SubMat(roi);
                        double maxVal, minVal;
                        OpenCvSharp.Point maxLoc, minLoc;
                        Cv2.MinMaxLoc(blockResult, out minVal, out maxVal, out minLoc, out maxLoc);

                        if (maxVal >= threshold)
                        {
                            // 找到匹配项，进行处理
                            int matchX = x + maxLoc.X;
                            int matchY = y + maxLoc.Y;
                            double minVal2, maxVal2;
                            OpenCvSharp.Point minLoc2, maxLoc2;
                            Cv2.MinMaxLoc(results[i], out minVal2, out maxVal2, out minLoc2, out maxLoc2);
                            Write($"匹配成功：最大匹配度{maxVal2},匹配位置{maxLoc2}", "Debug");
                            bl = true;
                            blockResult.Dispose();
                            return new Tuple<bool, double[]>(bl, new double[] { maxVal2, maxLoc2.X, maxLoc2.Y, minLoc2.X, minLoc2.Y });
                        }
                        blockResult.Dispose();
                    }
                }
            }
            // 停止计时
          //  stopwatch.Stop();
         //   Console.WriteLine("Run_多模型单图片识别_内存 Time elapsed: {0}", stopwatch.Elapsed);
            // 释放资源
            targetImg.Release();
            return new Tuple<bool, double[]>(bl, new double[] { });
        }
        private bool 算法检测(List<Mat> templates, byte[] imageData)
        {
            bool bl = false;//默认没有检测到

            //Write("开始检测" );
            Mat targetImg = new Mat();
            targetImg = Cv2.ImDecode(imageData, ImreadModes.Color);
            // 添加更多的模板...
            // 创建匹配结果矩阵列表
            List<Mat> results = new List<Mat>();

            foreach (Mat template in templates)
            {
                Mat result = new Mat();
                Cv2.MatchTemplate(targetImg, template, result, TemplateMatchModes.CCoeffNormed);
                results.Add(result);
                // template.Release(); // 释放模板资源
            }

            // 设置匹配阈值，根据需求调整
            double threshold = 匹配阈值;

            // 处理匹配结果
            for (int i = 0; i < results.Count; i++)
            {
                for (int y = 0; y < results[i].Rows; y++)
                {
                    for (int x = 0; x < results[i].Cols; x++)
                    {
                        float data = results[i].Get<float>(y, x);

                        if (data >= threshold)
                        {
                            // 找到匹配项，进行处理
                            Rect rectangle = new Rect(x, y, templates[i].Cols, templates[i].Rows);
                            Cv2.Rectangle(targetImg, rectangle, Scalar.Red, 2);

                            // 寻找最佳匹配位置
                            double minVal, maxVal;
                            OpenCvSharp.Point minLoc, maxLoc;
                            Cv2.MinMaxLoc(results[i], out minVal, out maxVal, out minLoc, out maxLoc);
                            Write("最大匹配度：" + maxVal, "Debug");
                            Write("匹配位置：" + maxLoc, "Debug");

                            if (maxVal > 最大匹配值)
                            {
                                bl = true;
                            }
                            //  string resultImagePath = 结果 + "\\" + Path.GetFileNameWithoutExtension(imgpath) +"-"+new Random().Next(0,9999999)+ ".png";
                            // targetImg.SaveImage(resultImagePath);
                        }
                    }
                }
            }

            targetImg.Release(); // 释放资源
            imageData = null;
            return bl;
        }
        #endregion
        #region 从文件路径图片识别
        private void 图像识别(string dir_模板文件夹, string 待检图片文件夹)
        {
            string[] files_模板 = Directory.GetFiles(dir_模板文件夹);
            if (files_模板.Length == 0 || files_模板 == null)
            {
                return;
            }
            //把读取的文件模板图，加载进识别列表
            List<Mat> templates = new List<Mat>();
            foreach (var item in files_模板)
            {
                templates.Add(Cv2.ImRead(item, ImreadModes.Color));

            }
            string[] files_待检图片 = Directory.GetFiles(待检图片文件夹);
            if (files_待检图片.Length == 0 || files_待检图片 == null)
            {
                return;
            }
            foreach (var item in files_待检图片)
            {
                new Task(() =>
                {
                    算法检测(templates, item);
                }).Start();

            }
            //把读取的文件图，加进列表，进行一个一个识别


            // 读取目标图片和模板图片列表

            // 显示结果
            //  BitmapSource source = BitmapSourceConverter.ToBitmapSource(targetImg);
            // targetImage.Source = source;
        }
        private bool 算法检测(List<Mat> templates, string imgpath)
        {

            bool bl = false;//默认没有检测到

            //Write("开始检测：" + imgpath);
            Mat targetImg = Cv2.ImRead(imgpath, ImreadModes.Color);
            // 添加更多的模板...
            // 创建匹配结果矩阵列表
            List<Mat> results = new List<Mat>();
            foreach (Mat template in templates)
            {
                Mat result = new Mat();
                Cv2.MatchTemplate(targetImg, template, result, TemplateMatchModes.CCoeffNormed);
                results.Add(result);


            }
            // 设置匹配阈值，根据需求调整
            double threshold = 匹配阈值;
            //   double 匹配度总和=0;//匹配度的和，是所有模板文件匹配度的总和。
            // 处理匹配结果
            for (int i = 0; i < results.Count; i++)
            {
                for (int y = 0; y < results[i].Rows; y++)
                {
                    for (int x = 0; x < results[i].Cols; x++)
                    {
                        float data = results[i].Get<float>(y, x);

                        if (data >= threshold)
                        {
                            // 找到匹配项，进行处理
                            Rect rectangle = new Rect(x, y, templates[i].Cols, templates[i].Rows);
                            Cv2.Rectangle(targetImg, rectangle, Scalar.Red, 2);

                            // 寻找最佳匹配位置
                            double minVal, maxVal;
                            OpenCvSharp.Point minLoc, maxLoc;
                            Cv2.MinMaxLoc(results[i], out minVal, out maxVal, out minLoc, out maxLoc);
                            // Console.WriteLine("已匹配到：" + imgpath);
                            if (maxVal > 最大匹配值)
                            {
                                bl = true;
                            }
                            // Console.WriteLine("最小匹配度：" + minVal);
                            Write($"{Path.GetFileName(imgpath)} 最大匹配度：" + maxVal, "Debug");

                            Write("匹配位置：" + maxLoc, "Debug");

                            //  string resultImagePath = 结果 + "\\" + Path.GetFileNameWithoutExtension(imgpath) +"-"+new Random().Next(0,9999999)+ ".png";
                            //  targetImg.SaveImage(resultImagePath);


                        }
                    }
                }
            }
            targetImg.Release();//释放资源   imgpath         
            return bl;
            //   double 最终匹配度 = 匹配度总和 / templates.Count;// 最终匹配度取决于多个模板匹配度的平均值
            // Console.WriteLine($"{Path.GetFileName(imgpath)}   匹配度总和：" + 匹配度总和);
            //  Console.WriteLine($"{Path.GetFileName(imgpath)}    templates.Count：" + templates.Count);
            //   Console.WriteLine($"{Path.GetFileName(imgpath)}   最终匹配度：" + 最终匹配度);

        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="dir"></param>
        private string[] 文件搜索(string dir)
        {

            if (Directory.Exists(dir))
            {
                string[] files = Directory.GetFiles(dir);
                return files;
            }
            else
            {
                return null;
            }
        }
        /// <summary>
        /// 开始识别图标算法
        /// </summary>
        /// <param name="dir_模板文件夹">模板文件夹</param>
        /// <param name="待检图片文件夹">待检图片文件夹</param>
        public async void Run(string dir_模板文件夹, string 待检图片文件夹)
        {
            await Task.Run(() =>
            {

                if (Directory.Exists(dir_模板文件夹) && Directory.Exists(待检图片文件夹))
                {
                    图像识别(dir_模板文件夹, 待检图片文件夹);
                }

            });


        }
        /// <summary>
        /// 开始识别图标算法
        /// </summary>
        /// <param name="dir_模板文件夹">模板文件夹</param>
        /// <param name="待检图片文件夹">待检图片文件夹</param>
        public async void Run_单图片识别(string dir_模板文件夹, string 待检图片路径, string 结果)
        {
            await Task.Run(() =>
            {

                if (Directory.Exists(dir_模板文件夹) && File.Exists(待检图片路径))
                {
                    单图像识别(dir_模板文件夹, 待检图片路径, 结果);
                    删除截图(待检图片路径);
                }

            });


        }
        void 删除截图(string a)
        {
            try
            {
                File.Delete(a);

            }
            catch (Exception ex)
            {
                // 捕获并处理异常

            }
        }
        private void 单图像识别(string dir_模板文件夹, string 待检图片路径, string 结果)
        {
            string[] files_模板 = Directory.GetFiles(dir_模板文件夹);
            if (files_模板.Length == 0 || files_模板 == null)
            {
                return;
            }
            //把读取的文件模板图，加载进识别列表
            List<Mat> templates = new List<Mat>();
            foreach (var item in files_模板)
            {
                templates.Add(Cv2.ImRead(item, ImreadModes.Color));

            }
            算法检测(templates, 待检图片路径);


        }
        #endregion
        //void Write(string str, string 错误级别)
        //{
        //    string a = DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss.fff");
        //    string stre = a + "\t" + this.GetType().Name + "\t" + 错误级别 + "\t" + str;
        //    //  Console.WriteLine(stre);
        //    File.AppendAllLines(logpath, new string[] { stre }, encoding: Encoding.UTF8);
        //}
        private static ConcurrentQueue<string> logQueue = new ConcurrentQueue<string>();
        private static AutoResetEvent autoResetEvent = new AutoResetEvent(false);
        private static Task writingTask = null;
        private static readonly object initializationLock = new object();
        private static object _lock = new object(); //写文件加锁
        void Write(string str, string 错误级别)
        {
            lock (_lock)
            {
                string a = DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss.fff");
                string stre = a + "\t" + this.GetType().Name + "\t" + 错误级别 + "\t" + str;
                Console.WriteLine(stre);
                using (StreamWriter streamWriter = new StreamWriter(logpath, true))
                {
                    streamWriter.WriteLine(stre);
                    streamWriter.Close();
                }
            }
        }
    }
}
